 /*
    作者：zx
    时间：2022.11.9
    描述：内核程序初始化
 */
 
 #include "os_cfg.h" 
    .text
    .extern kernel_init
    .global _start
    .extern init_main
_start:
    push %ebp
    mov %esp,%ebp
    mov 0x8(%esp),%eax

    # kernel_init(&boot_info)
    push %eax
    call kernel_init
    
    # 清流水线，改选择子
    jmp $KERNEL_SELECTOR_CS,$gdt_reload 

gdt_reload:
	mov $KERNEL_SELECTOR_DS, %ax
	mov %ax,%ds
	mov %ax,%ss
	mov %ax,%es
	mov %ax,%fs
	mov %ax,%gs

    mov $(stack+KERNEL_STACK_SIZE),%esp
    jmp init_main

    .bss
.comm stack,KERNEL_STACK_SIZE


# 异常处理程序,使用宏

# 宏定义
# .macro 宏名称 参数1 参数2 参数3
# ......
# .endm
#                      异常名称 异常号 是否存在错误码
.macro exception_handler name idx with_error_code
    .text
    .extern do_handler_\name
    .global exception_handler_\name 

exception_handler_\name:

    # 异常有错误码会自动压栈
    # 不存在错误码后时，就手动压入一个0
    .if \with_error_code==0
        push $0
    .endif

    push $\idx 
    pusha
    push %ds
    push %es
    push %fs
    push %gs

    # 把栈顶指针压入栈,此时栈顶指针是栈顶元素的地址，
    # 调用函数的参数是一个结构体地址，经过隐式转换
    # 这样就把一大块区域参数，传递给结构体了
    push %esp
    call do_handler_\name

    # 跳过之前压入的esp
    add $(1*4),%esp
    pop %gs
    pop %fs
    pop %es
    pop %ds
    popa

    # 跳过压入的idx和错误码
    add $(2*4),%esp
    iret
.endm


# 通过宏 生成exception_handler_unknown函数
# 宏名称           异常名称 异常号 没有错误码 
exception_handler unknown ,  -1 ,     0

# 通过宏 生成exception_handler_divder函数（除0错误）
# 异常号和有无错误码 需要查看手册
exception_handler divider,0,0
exception_handler debug,1,0
exception_handler NMI,2,0
exception_handler breakpoint,3,0
exception_handler overflow,4,0
exception_handler bound_range,5,0
exception_handler invalid_opcode,6,0
exception_handler device_not_available,7,0
exception_handler double_fault,8,1

exception_handler invalid_tss,10,1
exception_handler segement_not_present,11,1
exception_handler stack_segment_fault,12,1
exception_handler general_protection,13,1
exception_handler page_fault,14,1

exception_handler fpu_error,16,0
exception_handler alignment_check,17,1
exception_handler machine_check,18,0
exception_handler simd_exception,19,0
exception_handler virtual_exception,20,0
exception_handler control_exception,21,1

# 中断处理程序
# 时钟中断
exception_handler time,0x20,0
exception_handler kbd,0x21,0
exception_handler disk_primary,0x2E,0

    .text
    .global simple_switch
simple_switch:
    # from程序栈顶指针,值是&(task->stack) = &pesp
    # 是指针的地址,函数中的指针变动会影响到task->stack
    mov 4(%esp),%eax

    # to程序栈顶指针，值是to栈的task->stack = pesp
    # 是复制的指针，函数中的指针变动不会影响到task->stack
    mov 8(%esp),%edx

    push %ebp
    push %ebx
    push %edi
    push %esi

    # 将当前的栈顶指针，放到main task->stack
    # (%eax)代表取eax中的值，此时值是task->stack
    # 这句话等效为 *eax = main_task->stack = esp
    mov %esp,(%eax)

    # 将esp变为to程序的栈顶指针
    mov %edx,%esp
    # 弹出to栈中的寄存器
    pop %esi
    pop %edi
    pop %ebx
    pop %ebp
    # 弹出to栈中的eip，返回to程序继续执行
    ret

    .global exception_handler_syscall
    .extern do_handler_syscall
exception_handler_syscall:
    # 目前栈中从栈底开始 SS ESP id arg3-arg0 cs eip 
    # 再压入一部分寄存器的值，方便子进程复制
    pusha
    push %ds
    push %es
    push %fs
    push %gs
    pushf

    // 使用内核段寄存器，避免使用应用层的
	mov $(KERNEL_SELECTOR_DS), %eax
	mov %eax, %ds
	mov %eax, %es
	mov %eax, %fs
	mov %eax, %gs

    mov %esp,%eax
    push %eax
    call do_handler_syscall
    add $(1*4),%esp 

    popf
    pop %gs
    pop %fs
    pop %es
    pop %ds
    popa

    retf $(5*4) 